package com.wutianyi.images;

import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.ParameterBlock;
import java.awt.image.renderable.RenderContext;
import java.awt.image.renderable.RenderableImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.imageio.ImageIO;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import javax.media.jai.Warp;
import javax.media.jai.WarpGrid;
import javax.media.jai.widget.ScrollingImagePanel;

import org.microemu.app.capture.AnimatedGifEncoder;
import org.robotframework.abbot.editor.widgets.GifDecoder;

import com.sun.media.jai.codec.FileSeekableStream;
import com.sun.media.jai.codec.SeekableStream;
import com.sun.media.jai.codecimpl.PNGImageEncoder;

public class Main
{
    public static void main(String[] args) throws Exception
    {
        resizeGIF("gif-anime-bisou-1-gratuit.gif", "g_new.gif", 320, 240);
    }

    public static void resizeGIF(String source, String dist, int width, int height) throws Exception
    {
        // 读入处理的图片
        File srcImg = new File(source);
        // 将图片文件输入IO流
        InputStream is = new FileInputStream(srcImg);
        // 生成一个GifDecoder
        GifDecoder gifDecoder = new GifDecoder();
        if (GifDecoder.STATUS_FORMAT_ERROR == gifDecoder.read(is))
        {// 调用read方法读入文件流，出错时，抛出异常。
            throw new RuntimeException(// 自定义的一个异常类。
                    "The file to be resized is not a valid gif file.");
        }

        File destImg = new File(dist);
        OutputStream os = new FileOutputStream(destImg);
        // 动态画面编码器
        AnimatedGifEncoder animatedGifEncoder = new AnimatedGifEncoder();
        animatedGifEncoder.start(os);
        // 设置循环显示的次数
        animatedGifEncoder.setRepeat(gifDecoder.getLoopCount());
        animatedGifEncoder.setQuality(19);
        // 循环得到每一帧
        int frameCount = gifDecoder.getFrameCount();
        for (int i = 0; i < frameCount; i++)
        {
            BufferedImage sourceFrame = gifDecoder.getFrame(i);
            // 缩放
            /*
             * BufferedImage targetFrame = zoom(sourceFrame, width, height,
             * maxWidthLimit, maxHeigthLimit);
             */
            BufferedImage targetFrame = resize(sourceFrame, width, height);
            // 设置每帧显示间隔时间
            animatedGifEncoder.setDelay(gifDecoder.getDelay(i));
            animatedGifEncoder.addFrame(targetFrame);
        }
        animatedGifEncoder.finish();
    }

    /**
     * 判断一个文件类型名称，是否为图片类型
     * 
     * @param fileType
     *            文件类型名称
     * @return 是PNG, GIF, JPG图片类型为true否则为false
     */
    public static boolean isImage(String fileType)
    {
        if (isGif(fileType) || isJpg(fileType) || isPng(fileType))
            return true;
        else
            return false;
    }

    public static boolean isGif(String fileType)
    {
        if (fileType != null && fileType.trim().equalsIgnoreCase("GIF"))
            return true;
        else
            return false;
    }

    public static boolean isJpg(String fileType)
    {
        if (fileType != null && fileType.trim().equalsIgnoreCase("JPG"))
            return true;
        else
            return false;
    }

    public static boolean isPng(String fileType)
    {
        if (fileType != null && fileType.trim().equalsIgnoreCase("PNG"))
            return true;
        else
            return false;
    }

    /**
     * 获取图片文件的文件类型，JPG, PNG, GIF，如果非图片类型那么返回Undefined
     * 
     * @param srcFileName
     *            图片全路明
     * @return 图片文件类型JPG, PNG, GIF 如果非图片则为Undefined
     */
    public static String getImageType(String srcFileName)
    {
        FileInputStream imgFile = null;
        byte[] b = new byte[10];
        int l = -1;
        try
        {
            imgFile = new FileInputStream(srcFileName);
            l = imgFile.read(b);
            imgFile.close();
        }
        catch (Exception e)
        {
            return "Undefined";
        }
        if (l == 10)
        {
            byte b0 = b[0];
            byte b1 = b[1];
            byte b2 = b[2];
            byte b3 = b[3];
            byte b6 = b[6];
            byte b7 = b[7];
            byte b8 = b[8];
            byte b9 = b[9];
            if (b0 == (byte) 'G' && b1 == (byte) 'I' && b2 == (byte) 'F')
            {
                return "GIF";
            }
            else if (b1 == (byte) 'P' && b2 == (byte) 'N' && b3 == (byte) 'G')
            {
                return "PNG";
            }
            else if (b6 == (byte) 'J' && b7 == (byte) 'F' && b8 == (byte) 'I' && b9 == (byte) 'F')
            {
                return "JPG";
            }
            else
            {
                return "Undefined";
            }
        }
        else
        {
            return "Undefined";
        }
    }

    /**
     * JPG文件Resize方法
     * 
     * @param source
     *            源文件地址
     * @param dist
     *            目标文件地址
     * @param width
     *            目标宽度
     * @param height
     *            目标高度
     * @throws Exception
     *             异常信息
     */
    public static void resizeJPG(String source, String dist, int width, int height) throws Exception
    {
        if (!isJpg(getImageType(source)))
            throw new Exception("The source file is not a jpeg file or not exist!");
        BufferedImage sourceImage = ImageIO.read(new File(source));
        BufferedImage targetImage = resize(sourceImage, width, height);
        ImageIO.write(targetImage, "jpg", new File(dist));
    }

    /**
     * 实现图像的等比缩放
     * 
     * @param source
     * @param targetW
     * @param targetH
     * @return
     */
    private static BufferedImage resize(BufferedImage source, int targetW, int targetH)
    {
        // targetW，targetH分别表示目标长和宽
        int type = source.getType();
        BufferedImage target = null;
        double sx = (double) targetW / source.getWidth();
        double sy = (double) targetH / source.getHeight();
        // 这里想实现在targetW，targetH范围内实现等比缩放。如果不需要等比缩放
        // 则将下面的if else语句注释即可
        if (sx < sy)
        {
            // sx = sy;
            targetW = (int) (sx * source.getWidth());
        }
        else
        {
            // sy = sx;
            targetH = (int) (sy * source.getHeight());
        }
        if (type == BufferedImage.TYPE_CUSTOM)
        { // handmade
            ColorModel cm = source.getColorModel();
            WritableRaster raster = cm.createCompatibleWritableRaster(targetW, targetH);
            boolean alphaPremultiplied = cm.isAlphaPremultiplied();
            target = new BufferedImage(cm, raster, alphaPremultiplied, null);
        }
        else
            target = new BufferedImage(targetW, targetH, type);
        Graphics2D g = target.createGraphics();
        // smoother than exlax:
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
        g.dispose();
        return target;
    }

    /**
     * 实现图像的等比缩放和缩放后的截取
     * 
     * @param inFilePath
     *            要截取文件的路径
     * @param outFilePath
     *            截取后输出的路径
     * @param width
     *            要截取宽度
     * @param hight
     *            要截取的高度
     * @param proportion
     * @throws Exception
     */
    public static void saveImageAsJpg(String inFilePath, String outFilePath, int width, int hight, boolean proportion)
            throws Exception
    {
        File file = new File(inFilePath);
        InputStream in = new FileInputStream(file);
        File saveFile = new File(outFilePath);
        BufferedImage srcImage = ImageIO.read(in);
        if (width > 0 || hight > 0)
        {
            // 原图的大小
            int sw = srcImage.getWidth();
            int sh = srcImage.getHeight();
            // 如果原图像的大小小于要缩放的图像大小，直接将要缩放的图像复制过去
            if (sw > width && sh > hight)
            {
                srcImage = resize(srcImage, width, hight);
            }
            else
            {
                String fileName = saveFile.getName();
                String formatName = fileName.substring(fileName.lastIndexOf('.') + 1);
                ImageIO.write(srcImage, formatName, saveFile);
                return;
            }
        }
        // 缩放后的图像的宽和高
        int w = srcImage.getWidth();
        int h = srcImage.getHeight();
        // 如果缩放后的图像和要求的图像宽度一样，就对缩放的图像的高度进行截取
        if (w == width)
        {
            // 计算X轴坐标
            int x = 0;
            int y = h / 2 - hight / 2;
            saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
        }
        // 否则如果是缩放后的图像的高度和要求的图像高度一样，就对缩放后的图像的宽度进行截取
        else if (h == hight)
        {
            // 计算X轴坐标
            int x = w / 2 - width / 2;
            int y = 0;
            saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
        }
        in.close();
    }

    /**
     * 实现缩放后的截图
     * 
     * @param image
     *            缩放后的图像
     * @param subImageBounds
     *            要截取的子图的范围
     * @param subImageFile
     *            要保存的文件
     * @throws IOException
     */
    private static void saveSubImage(BufferedImage image, Rectangle subImageBounds, File subImageFile)
            throws IOException
    {
        if (subImageBounds.x < 0 || subImageBounds.y < 0 || subImageBounds.width - subImageBounds.x > image.getWidth()
                || subImageBounds.height - subImageBounds.y > image.getHeight())
        {
            System.out.println("Bad   subimage   bounds");
            return;
        }
        BufferedImage subImage = image.getSubimage(subImageBounds.x, subImageBounds.y, subImageBounds.width,
                subImageBounds.height);
        String fileName = subImageFile.getName();
        String formatName = fileName.substring(fileName.lastIndexOf('.') + 1);
        ImageIO.write(subImage, formatName, subImageFile);
    }
}
